/**
* $Id: TileMap.as 67 2006-08-13 15:49:35Z miller $
*/
package
{
	import mx.containers.Canvas;
	import flash.ui.Mouse;
	import flash.events.MouseEvent;
	import flash.events.Event;
	import mx.core.UIComponent;
	import flash.display.BitmapData;
	import flash.display.Bitmap;
	import mx.controls.Image;
	import flash.events.HTTPStatusEvent;
	import flash.display.Loader;
	import flash.net.URLRequest;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.display.MovieClip;
	import mx.managers.LayoutManager;

	public class TileMap extends UIComponent
	{
		internal var viewX : int, viewY : int, viewHeight : int, viewWidth : int;
		public var worldWidth : int, worldHeight : int;
		
		public var imgTileset : Bitmap, imgBuffer : Bitmap;
		
		internal var nTileRows : int, nTileCols : int;
		internal var scale : Number = 1;
		
		internal var grid : Array;
				
		public function TileMap()
		{
			super();
			viewX = viewY = 0;
			viewWidth = this.width / scale;
			viewHeight = this.height / scale;
			
			backgroundColor = 0xFF000000;
			
		}
		
		public function getScale() : Number {
			return scale;
		}

		public function setScale( sc : Number ) : void {
			if( sc < 0.35 || sc > 5 ) 
				return;
			scale = sc;
			updateDisplayList( width, height );
			renderMap();			
		}
		
		override protected function updateDisplayList( unscaledWidth:Number, unscaledHeight:Number ) : void {
//			width = unscaledWidth
//			height = unscaledHeight
			trace( "updateDisplayList ", unscaledWidth, unscaledHeight );
			viewWidth = unscaledWidth / scale;
			viewHeight = unscaledHeight / scale;
			
			if( imgBuffer != null ) {
				imgBuffer.parent.removeChild( imgBuffer );
				imgBuffer.bitmapData.dispose();
			}
			imgBuffer = new Bitmap( new BitmapData( viewWidth, viewHeight ));
			imgBuffer.scaleX = scale;
			imgBuffer.scaleY = scale;
			addChild( imgBuffer );
			renderMap();
			
		}
		internal var nMapCols : int, nMapRows : int;
		internal var nTileWidth : int, nTileHeight : int
		
		public function init( nCols : int, nRows : int, tileWidth : int, tileHeight : int ) :void {
			backgroundColor |= 0xFF000000;
						
			nMapCols = nCols;
			nMapRows = nRows;
			nTileWidth = tileWidth;
			nTileHeight = tileHeight;
			worldHeight = nTileHeight * nRows
			worldWidth = nTileWidth * nCols	
			
			grid = new Array(nMapCols * nMapRows);
			
			imgBuffer = new Bitmap( new BitmapData( this.width / scale, this.height / scale ));
			imgBuffer.scaleX = scale;
			imgBuffer.scaleY = scale;
				
			addChild( imgBuffer );
		}
		
		public function pickRow( y : int ) : int {
			return Math.floor(( viewY + y ) / nTileHeight );
		}
		
		public function pickCol( x : int ) : int {
			return Math.floor(( viewX + x  )/ nTileWidth );
		}
		
		public function onTileSetLoaded( evt : Event ) : void {
			var loader : Loader = Loader( evt.target.loader );
			var bitmap : Bitmap = Bitmap( loader.content );

			imgTileset = bitmap;
			nTileRows = imgTileset.height / nTileHeight;
			nTileCols = imgTileset.width / nTileWidth;			
			
			renderMap();
		}
		
		public function setTileSet( filename : String ) : void {
			var loader : Loader = new Loader();
			loader.contentLoaderInfo.addEventListener( Event.COMPLETE, onTileSetLoaded );
			loader.contentLoaderInfo.addEventListener( "httpStatus", function ( evt: HTTPStatusEvent ) : void {
				trace( 'http status', evt.status );
			} );
			loader.load( new URLRequest( filename ));
//			trace( "image ",img," width ",img.width )
//			imgTileset = new BitmapData( 
		}
		
		
		public function setViewWindow( left : int, top : int, width : int, height : int ) : void {
			viewWidth = width / scale;
			viewHeight = height / scale;
			scroll( left - viewX, top - viewY );			
		}
		public var backgroundColor : int;
		
		public function getColumns() : int {
			return nMapCols;
		}
		public function getRows() : int {
			return nMapRows;
		}
		
 		public function setCell( col : int, row : int, tile : int ) : void {
 			grid[ row * nMapCols + col ] = tile; 			
 		}
 		
 		public function getCell( col : int, row : int ) : int {
//			var t : int = ( row * nMapCols + col ) % ( nTileRows * nTileCols );
			if( grid == null || row >= nMapRows || row < 0 || col >= nMapCols || col < 0 )
				return 0;
			return grid[ row * nMapCols + col ];
		}
		
		public function scroll( dx : int, dy : int ) : void {
			imgBuffer.bitmapData.scroll( -dx, -dy );
			
			viewX += dx;
			viewY += dy;
			
			var firstRow : int, firstCol : int, lastRow : int, lastCol : int;
			
			firstRow = Math.floor( viewY / ( nTileHeight )) - 1;
			lastRow = firstRow + Math.ceil(( viewHeight )/ nTileHeight ) + 1;
			
			if( dx < 0 ) {
				lastCol = Math.floor(( viewX - dx )/ ( nTileWidth ));
				firstCol = Math.floor(( viewX )/ (  nTileWidth ));
			} else {
				firstCol = Math.floor(( viewX + viewWidth - dx )/ ( nTileWidth ));
				lastCol = Math.floor(( viewX + viewWidth )/ nTileWidth );
			}
			renderRegion( firstRow, firstCol, lastRow, lastCol );
			
			trace( "scroll "+dx+" to "+viewX+": firstRow, lastRow, firstCol, lastCol "+[firstRow, lastRow, firstCol, lastCol ]);
			
			firstCol = Math.floor( viewX / nTileWidth ) - 1;
			lastCol = firstCol + Math.ceil( viewWidth / nTileWidth ) + 1;
			
			if( dy < 0 ) {
				lastRow = Math.floor( ( viewY - dy )/ ( nTileHeight ));
				firstRow = Math.floor(( viewY )/ ( nTileHeight ));
			} else {
				firstRow = Math.floor(( viewY + viewHeight - dy )/ (  nTileHeight ));
				lastRow = Math.floor(( viewY + viewHeight )/  nTileHeight );
			}
			renderRegion( firstRow, firstCol, lastRow, lastCol );
		}
		
		public function renderMap() : void {
			
/*
			graphics.clear();
			graphics.lineStyle( 1, 0xFF0000 );
			graphics.drawCircle( 300 - viewX , 200 - viewY, 50 );
			graphics.drawCircle( 0 - viewX, 0 - viewY, 10 );
*/			
			var firstRow : int, firstCol : int, lastRow : int, lastCol : int;
			
			firstRow = Math.floor( viewY / nTileHeight ) - 1;
			firstCol = Math.floor( viewX / nTileWidth ) - 1;
			lastRow = firstRow + Math.ceil(( height )/ ( scale * nTileHeight )) + 1;
			lastCol = firstCol + Math.ceil(( width )/ ( scale * nTileWidth )) + 1;
			
			renderRegion( firstRow, firstCol, lastRow, lastCol );
		}
			
		public function renderRegion( firstRow : int, firstCol : int, lastRow : int, lastCol : int ) : void {
			var i : int, j : int;
			var t : int;
//			trace( "firstCol, lastCol, width, nTileWidth "+[ firstCol, lastCol, width, nTileWidth ] )
			
			var rectSrc : Rectangle = new Rectangle(
				 -viewX + firstCol*nTileWidth, -viewY + firstRow*nTileHeight, 
				 ( lastCol - firstCol + 1 )*nTileWidth , ( lastRow - firstRow + 1 )*nTileHeight );
			var ptDest : Point = new Point();
			var bmpBuffer : BitmapData = imgBuffer.bitmapData;
			
			imgBuffer.visible = false;
			
			bmpBuffer.fillRect( rectSrc, backgroundColor );
			
			rectSrc.width = nTileWidth;
			rectSrc.height = nTileHeight;			
			ptDest.y = -viewY + firstRow*nTileHeight;
			
			for( i = firstRow; i <= lastRow; i++ ) {
				ptDest.x = -viewX + firstCol*nTileWidth;
				for( j = firstCol; j <= lastCol; j++ ) {
					t = getCell( j, i );
					if( t > 0 ) {
						t--;
						rectSrc.y = Math.floor( t / nTileCols ) * nTileHeight ;
						rectSrc.x = ( t % nTileCols ) * nTileWidth;			
//						trace( "i, j, rectSrc, t "+[ i, j, rectSrc.x, rectSrc.y, t ] )
						bmpBuffer.copyPixels( imgTileset.bitmapData, rectSrc, ptDest );
					}
					ptDest.x += nTileWidth;
				}				
				ptDest.y += nTileHeight;
			}
			
			imgBuffer.visible = true;			
		}		
		

		public function loadXMLMapData( mapXML : XML ) : Boolean {
			var urlTileSet : String = mapXML.tileset.@url;
			
			if( !urlTileSet )
				return false;
			if( !mapXML.@width || mapXML.@width < 0 )
				return false;
			if( !mapXML.@height || mapXML.@height < 0 )
				return false;

			init( mapXML.@width, mapXML.@height, mapXML.tileset.@width, mapXML.tileset.@height );
			setTileSet( urlTileSet );
			
			var strGrid : String = mapXML.layer.toString()
			var arrGrid : Array = strGrid.split( "," );
			var row : int = 0, col : int = 0, i : int;
			for( i=0; i < arrGrid.length; i++ ) {
				setCell( col, row, arrGrid[i] );
				col++;
				if( col >= getColumns() ) {
					col = 0; row++;
					if( row >= getRows() )
						break;
				}
			}
			//TODO check errors
			return true;
		}
	}

}